package com.linko.intelligent.common.util;


import com.linko.intelligent.base.Node;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

public class TreeUtil {

    public static List<Node> buildTreeToList(Node tree) {
        List<Node> nodes = new ArrayList<>();
        buildTreeToList(tree, nodes);
        return nodes;
    }

    private static void buildTreeToList(Node tree, List<Node> nodes) {
        if (tree == null) {
            return;
        }
        if (nodes == null) {
            nodes = new ArrayList<>();
        }
        nodes.add(tree);
        if (tree.getChildren() != null) {
            for (Object child : tree.getChildren()) {
                buildTreeToList((Node) child, nodes);
            }
        }

    }

    public static List<Node> buildListToTree(List<Node> dirs, Boolean cleanId) {
        List<Node> roots = findRoots(dirs);
        //分组
        Map<String, List<Node>> collect = dirs.stream().collect(Collectors.groupingBy(Node::getParentId));
        //拼接数据
        for (Node root : roots) {
            forEach(collect, root);
        }
        if (cleanId != null && cleanId) {
            if (roots != null && roots.size() > 0) {
                for (Node node : roots) {
                    clearId(node);
                }
            }
        }
        return roots;
    }

    private static void forEach(Map<String, List<Node>> collect, Node root) {
        List<Node> childs = new ArrayList<>();
        childs = collect.get(root.getId());
        if (childs != null && childs.size() > 0) {
            //排序
            childs.stream()
                    .map(item -> {
                        item.setParent(root);
                        item.setLevel(root.getLevel() + 1);
                        return item;
                    })
                    .sorted(Comparator.comparing(Node::getId))
                    .collect(Collectors.toList());
            root.setChildren(childs);
            root.setLeaf(false);
            childs.forEach(t -> {
                forEach(collect, t);
            });
        } else {
            root.setChildren(childs);
            root.setLeaf(true);
        }
    }


    public static List<Node> findRoots(List<Node> allNodes) {
        List<Node> results = new ArrayList<Node>();
        for (Node node : allNodes) {
            String parentId = node.getParentId();
            if (parentId.indexOf(":") > -1) {
                parentId = parentId.split(":")[1];
            }
            if (StringUtils.isBlank(parentId) || "0".equals(parentId)) {
                results.add(node);
            }
        }
        if (results.size() == 0) {
            results = findRootsByMatch(allNodes);
        }
        return results;
    }

    //耗时比较严重
    public static List<Node> findRootsByMatch(List<Node> allNodes) {
        List<Node> results = new ArrayList<Node>();
        for (Node node : allNodes) {
            boolean isRoot = true;
            for (Node comparedOne : allNodes) {
                if (comparedOne.getId().equals(node.getParentId())) {
                    isRoot = false;
                    break;
                }
            }
            if (isRoot) {
                node.setLevel(0);
                results.add(node);
                node.setRootId(node.getId());
            }
        }
        return results;
    }

    @SuppressWarnings("unchecked")
    public static List<Node> findChildren(Node root, List<Node> allNodes) {
        List<Node> children = new ArrayList<Node>();

        for (Node comparedOne : allNodes) {
            if (root.getId().equals(comparedOne.getParentId())) {
                comparedOne.setParent(root);
                comparedOne.setLevel(root.getLevel() + 1);
                children.add(comparedOne);
            }
        }
        List<Node> notChildren = (List<Node>) CollectionUtils.subtract(allNodes, children);
        for (Node child : children) {
            List<Node> tmpChildren = findChildren(child, notChildren);
            if (tmpChildren == null || tmpChildren.size() == 0) {
                child.setLeaf(true);
            } else {
                child.setLeaf(false);
            }
            child.setChildren(tmpChildren);
        }
        return children;
    }


    public static Node queryNodeById(Node tree, String id) {
        List<Node> tars = new ArrayList<>();
        queryNodeById(tree, id, tars);
        if (tars.size() > 0) {
            return tars.get(0);
        }
        return null;
    }

    private static void queryNodeById(Node tree, String id, List<Node> tars) {
        if (StringUtils.isNotBlank(tree.getId()) && tree.getId().equals(id)) {
            tars.add(tree);
        } else {
            if (tree.getChildren() != null && tree.getChildren().size() > 0) {
                for (Object tre : tree.getChildren()) {
                    queryNodeById((Node) tre, id, tars);
                }
            }
        }
    }

    public static List<Node> queryNodeByType(Node tree, String type) {
        List<Node> tars = new ArrayList<>();
        queryNodeByType(tree, type, tars);
        return tars;
    }

    private static void queryNodeByType(Node tree, String type, List<Node> tars) {
        if (StringUtils.isNotBlank(tree.getType()) && tree.getType().equals(type)) {
            tars.add(tree);
        } else {
            Node parent = tree.getParent();
            if (parent != null) {
                queryNodeByType(parent, type, tars);
            }
        }
    }

    //获取级联名字
    public static String cascadeName(Node node) {
        List<String> names = new ArrayList<>();
        cascadeName(node, names);
        Collections.reverse(names);
        names.add(node.getName());
        return String.join("#", names);
    }

    private static void cascadeName(Node node, List<String> names) {
        if (node.getParent() != null) {
            names.add(node.getParent().getName());
            cascadeName(node.getParent(), names);
        }
    }

    public static List<Node> findLeafs(Node node, String type) {
        List<Node> tars = new ArrayList<>();
        findLeafs(node, type, tars);
        return tars;
    }

    //递归寻找叶子节点
    private static void findLeafs(Node node, String type, List<Node> tars) {
        if (node.isLeaf()) {
            if (type == null) {
                tars.add(node);
            } else {
                if (type.equals(node.getType())) {
                    tars.add(node);
                }
            }

        } else {
            List<Node> nodes = node.getChildren();
            for (Node n : nodes) {
                findLeafs(n, type, tars);
            }
        }

    }

    //清除id的类型
    public static void clearId(Node node) {
        if (node.getId().indexOf(":") > -1) {
            node.setId(node.getId().split(":")[1]);
        }
        if (StringUtils.isNotBlank(node.getParentId()) && node.getParentId().indexOf(":") > -1) {
            node.setParentId(node.getParentId().split(":")[1]);
        }
        if (node.getChildren() != null && node.getChildren().size() > 0) {
            for (Object n : node.getChildren()) {
                clearId((Node) n);
            }
        }
    }


    public static void main(String[] args) {
//        TreeBuilder tb = new TreeBuilder();
        List<Node> allNodes = new ArrayList<Node>();
        allNodes.add(new Node("" + 1, "" + 0, "节点1"));
        allNodes.add(new Node("" + 2, "" + 0, "节点2"));
        allNodes.add(new Node("" + 3, "" + 0, "节点3"));
        allNodes.add(new Node("" + 4, "" + 1, "节点4"));
        allNodes.add(new Node("" + 5, "" + 1, "节点5"));
        allNodes.add(new Node("" + 6, "" + 1, "节点6"));
        allNodes.add(new Node("" + 7, "" + 4, "节点7"));
        allNodes.add(new Node("" + 8, "" + 4, "节点8"));
        allNodes.add(new Node("" + 9, "" + 5, "节点9"));
        allNodes.add(new Node("" + 10, "" + 100, "节点10"));
        List<Node> roots = buildListToTree(allNodes, true);
        for (Node n : roots) {
            System.out.println(n);
        }
    }
}